﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Slf;
using System.Reflection;

namespace SLF.Test
{
  [TestClass]
  public class LoggerBaseTest
  {
    /// <summary>
    /// All public methods, other than Log(LogItem) and the Name property accessor.
    /// </summary>
    List<MethodInfo> methods = typeof(ILogger)
                .GetMethods()
                .Where(m => !(m.Name == "Log" || m.Name=="get_Name"))
                .ToList();

    [TestMethod]
    public void Ensure_Logger_Name_Logged_For_All_Methods()
    {
      TestLogger logger = new TestLogger("LoggerName");

      foreach (MethodInfo method in methods)
      {
        logger.Reset();

        var args = ExploratoryTester.CreateArgumentList(method);
        method.Invoke(logger, args.ToArray());

        Assert.AreEqual(1, logger.LoggedItems.Count, "An item was not logged");
        Assert.AreEqual("LoggerName", logger.LoggedItems[0].LoggerName,
          "Logger name not written " + method.ToString());
      }
    }

    [TestMethod]
    public void Ensure_Message_Logged_For_All_Methods()
    {
      TestLogger logger = new TestLogger("LoggerName");

      var methodsWithMessage = methods
        .Where(m => m.GetParameters().Where(p => p.Name == "message").Count() != 0);

      foreach (MethodInfo method in methodsWithMessage)
      {
        logger.Reset();

        // create an argument list with our message
        var args = ExploratoryTester.CreateArgumentList(method);

        var parms = method.GetParameters().ToList();
        int indx = parms.IndexOf(parms.Where(p => p.Name == "message").Single());
        args[indx] = "Test Message";

        method.Invoke(logger, args.ToArray());

        Assert.AreEqual(1, logger.LoggedItems.Count, "An item was not logged");
        Assert.AreEqual("Test Message", logger.LoggedItems[0].Message,
          "Logger message not written " + method.ToString());
      }
    }

    [TestMethod]
    public void Ensure_Method_Logs_Correct_Level()
    {
      TestLogger logger = new TestLogger("LoggerName");

      var methodsWithLevel = methods
        .Where(m => !(m.Name=="Log"));

      foreach (MethodInfo method in methodsWithLevel)
      {
        logger.Reset();

        // create an argument list with our message
        var args = ExploratoryTester.CreateArgumentList(method);

        method.Invoke(logger, args.ToArray());

        Assert.AreEqual(1, logger.LoggedItems.Count, "An item was not logged " + method.Name);

        if (method.Name.Contains("Debug"))
          Assert.AreEqual(LogLevel.Debug, logger.LoggedItems[0].LogLevel);
        else if (method.Name.Contains("Info"))
          Assert.AreEqual(LogLevel.Info, logger.LoggedItems[0].LogLevel);
        else if (method.Name.Contains("Error"))
          Assert.AreEqual(LogLevel.Error, logger.LoggedItems[0].LogLevel);
        else if (method.Name.Contains("Fatal"))
          Assert.AreEqual(LogLevel.Fatal, logger.LoggedItems[0].LogLevel);
        else if (method.Name.Contains("Warn"))
          Assert.AreEqual(LogLevel.Warn, logger.LoggedItems[0].LogLevel);
        else
          Assert.Fail(method.Name);
        

        
      }
    }
  }
}
